package org.dromara.common.sensitive.handler;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveService;
import org.dromara.common.sensitive.core.SensitiveStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;

import java.io.IOException;
import java.util.Objects;


/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：数据脱敏json序列化工具
 */
/**
 * SensitiveHandler类用于处理敏感信息的序列化
 * 它继承了JsonSerializer<String>，实现了ContextualSerializer接口
 * 该类的目的是确保敏感信息在转换为JSON格式时能够进行适当的处理，以保护隐私
 */
@Slf4j
public class SensitiveHandler extends JsonSerializer<String> implements ContextualSerializer {

    /**
     * 脱敏策略
     */
    private SensitiveStrategy strategy;

    /**
     * 角色键值，用于标识不同的角色
     */
    private String roleKey;

    /**
     * 权限字符串，用于定义特定的操作权限
     */
    private String perms;

    /**
     * 将指定的字符串值序列化为JSON，支持敏感信息的脱敏处理
     *
     * @param value 待序列化的字符串值
     * @param gen 用于写入序列化后的JSON的生成器
     * @param serializers 序列化器提供者，用于获取上下文信息和调用其他序列化器
     * @throws IOException 如果写入过程中发生I/O错误
     */
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 尝试获取敏感服务Bean，用于判断和执行敏感信息的脱敏处理
        try {
            SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class);
            // 检查敏感服务是否可用，并判断当前角色和权限是否需要脱敏
            if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive(roleKey, perms)) {
                // 如果需要脱敏，则使用策略中定义的脱敏器处理值
                gen.writeString(strategy.desensitizer().apply(value));
            } else {
                // 如果不需要脱敏，直接写入原值
                gen.writeString(value);
            }
        } catch (BeansException e) {
            // 如果获取敏感服务Bean失败，记录错误并直接写入原值
            log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage());
            gen.writeString(value);
        }
    }

    /**
     * 创建此序列化器的上下文敏感版本
     * 如果属性被@Sensitive注解标记且为字符串类型，则使用注解中定义的策略和参数进行敏感信息脱敏
     * 否则，返回默认的序列化器
     *
     * @param prov 序列化提供器，用于查找和创建序列化器
     * @param property 正在处理的属性，可能带有@Sensitive注解
     * @return 返回敏感信息脱敏的序列化器实例，或默认序列化器
     * @throws JsonMappingException 如果无法创建合适的序列化器，则抛出此异常
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        // 获取属性上的@Sensitive注解
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        // 检查注解是否存在且属性类型为String
        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
            // 如果条件满足，设置脱敏策略、角色键和权限值
            this.strategy = annotation.strategy();
            this.roleKey = annotation.roleKey();
            this.perms = annotation.perms();
            // 返回当前实例以进行敏感信息脱敏
            return this;
        }
        // 如果条件不满足，返回默认的序列化器
        return prov.findValueSerializer(property.getType(), property);
    }
}
